package com.sdy.healthcode.biz.service.impl;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.sdy.common.model.BizException;
import com.sdy.common.utils.Assert;
import com.sdy.common.utils.DateUtil;
import com.sdy.common.utils.MapUtil;
import com.sdy.healthcode.biz.constants.HealthCodeType;
import com.sdy.healthcode.biz.dto.CommunityActionDTO;
import com.sdy.healthcode.biz.dto.FamilyMember;
import com.sdy.healthcode.biz.dto.UserActionPost;
import com.sdy.healthcode.biz.model.ApplyPost;
import com.sdy.healthcode.biz.model.BayonetManage;
import com.sdy.healthcode.biz.model.HealthCode;
import com.sdy.healthcode.biz.model.Region;
import com.sdy.healthcode.biz.model.User;
import com.sdy.healthcode.biz.model.UserAction;
import com.sdy.healthcode.biz.mapper.UserActionMapper;
import com.sdy.healthcode.biz.service.ApplyPostService;
import com.sdy.healthcode.biz.service.BayonetManageService;
import com.sdy.healthcode.biz.service.HealthCodeService;
import com.sdy.healthcode.biz.service.RegionService;
import com.sdy.healthcode.biz.service.UserActionService;
import com.sdy.healthcode.biz.service.UserService;
import com.sdy.mvc.service.impl.BaseServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author zzq
 * @since 2020-02-18
 */
@Slf4j
@Service
public class UserActionServiceImpl extends BaseServiceImpl<UserAction> implements UserActionService {
    @Autowired
    private UserActionMapper userActionMapper;
    @Autowired
    private RegionService regionService;
    @Autowired
    private UserService userService;
    @Autowired
    private ApplyPostService applyPostService;
    @Autowired
    private HealthCodeService healthCodeService;
    @Autowired
    private BayonetManageService bayonetManageService;

    @Override
    public void takeAction(UserActionPost userActionPost, HealthCode healthCode) throws BizException {
        String accompanyUserStr = null;
        ApplyPost applyPost = applyPostService.queryApplyPost(userActionPost.getUserId());
        Assert.isNull(applyPost, "找不到用户预约记录。");
        if (healthCode.getType().equals(1) || healthCode.getType().equals(2)) {
            accompanyUserStr = String.join("##", FamilyMember.fromStr(applyPost.getFamilyMember()).stream().map(FamilyMember::getPhone).collect(Collectors.toList()));
        }
        Date now = new Date();
        User recorder = userService.getById(userActionPost.getRecorderId());
        BayonetManage bayonetManage = bayonetManageService.lambdaQuery()
                .eq(BayonetManage::getBayonetToken, userActionPost.getTk())
                .last("limit 1")
                .one();
        if (bayonetManage != null) {
            Assert.isTrue(bayonetManage.getState() == 0, "该二维码已被禁用!");
        }
        UserAction userAction = new UserAction()
                .setUserId(userActionPost.getUserId())
                .setAction(userActionPost.getAction())
                .setHealthStatus(userActionPost.getHealthStatus())
                .setStrategy(userActionPost.getStrategy())
                .setRecorderId(userActionPost.getRecorderId())
                .setRecordDate(DateUtil.getDate(now, "yyyyMMdd"))
                .setRecordTime(now)
                .setRecordAddr(recorder.getMonitorCommunity())
                .setHealthCodeId(healthCode.getId())
                .setAccompanyUser(accompanyUserStr)
                .setType(healthCode.getType())
                .setGoOut(userActionPost.getGoOut())
                .setBayonetManageId(bayonetManage == null ? null : bayonetManage.getId())
                .setRemark(userActionPost.getRemark())
                .setVehicleId(userActionPost.getVehicleId());
        save(userAction);
        // 进出信息与码不符更新分控码
        if(userAction.getHealthStatus() == 1 && !"G".equals(healthCode.getHcode())){
            healthCodeService.updateHealthCode(HealthCodeType.GREEN, userAction.getUserId(), "action:" + userAction.getId());
        }else if(userAction.getHealthStatus() == 2 && !"R".equals(healthCode.getHcode())) {
            healthCodeService.updateHealthCode(HealthCodeType.RED, userAction.getUserId(), "action:" + userAction.getId());
        }
/*        if (userAction.getHealthStatus().equals(2)) {
            log.info("用户[{}]扫码健康状态异常，更新健康码 ? -> R", userAction.getUserId());
            healthCodeService.updateHealthCode(HealthCodeType.RED, userAction.getUserId(), "action:" + userAction.getId());
        }*/
    }

    @Override
    public Integer countUserAction(Integer userId) {
        return lambdaQuery().eq(UserAction::getUserId, userId).count();
    }

    @Override
    public IPage<CommunityActionDTO> pageCommunityAction(IPage<CommunityActionDTO> page, String areaCode) {
        List<CommunityActionDTO> resultList = new ArrayList<>();
        IPage<Region> communityPage = regionService.pageCommunityByArea(new Page<>(page.getCurrent(), page.getSize()), areaCode);
        if (communityPage.getRecords().isEmpty()) {
            return new Page<CommunityActionDTO>(page.getCurrent(), page.getSize(), 0).setRecords(Collections.emptyList());
        }
        List<UserAction> record = lambdaQuery()
                .in(UserAction::getRecordAddr, communityPage.getRecords().stream().map(Region::getCommunityCode).collect(Collectors.toSet()))
                .eq(UserAction::getRecordDate, DateUtil.getDate(new Date(), "yyyyMMdd"))
                .eq(UserAction::getStrategy, 1)
                .list();
        Map<String, List<UserAction>> m = MapUtil.collectionToMapList(record, UserAction::getRecordAddr);
        
        communityPage.getRecords().forEach(community -> {
            List<Integer> userIdInList = new ArrayList<>();
            List<Integer> userIdOutList = new ArrayList<>();
            List<UserAction> userActions = m.getOrDefault(community.getCommunityCode(), Collections.emptyList());
            Integer managerId = null;
            for (UserAction action : userActions) {
                if (action.getAction().equals(1)) {
                    userIdInList.add(action.getUserId());
                } else if (action.getAction().equals(2)) {
                    userIdOutList.add(action.getUserId());
                }
                managerId = action.getRecorderId();
            }
            Set<Integer> userIdInSet = new HashSet<>(userIdInList);
            Set<Integer> userIdOutSet = new HashSet<>(userIdOutList);
            
            Set<Integer> userInOutSet = new HashSet<>();
            // 进出>2次的人
            for (Integer uid : userIdInSet) {
                long cnt = userIdInList.stream().filter(item -> item.equals(uid)).count();
                if (cnt > 2) {
                    userInOutSet.add(uid);
                }
            }
            for (Integer uid : userIdOutSet) {
                long cnt = userIdOutList.stream().filter(item -> item.equals(uid)).count();
                if (cnt > 2) {
                    userInOutSet.add(uid);
                }
            }
            CommunityActionDTO dto = new CommunityActionDTO();
            dto.setComminutyCode(community.getCommunityCode())
                    .setComminutyName(community.getCommunityName())
                    .setManagerId(managerId)
                    .setIn(userIdInSet.size())
                    .setOut(userIdOutSet.size())
                    .setInOutTwice(userInOutSet.size());
            resultList.add(dto);
        });
        // 查询管理员信息
        Set<Integer> userIdSet = resultList.stream().map(CommunityActionDTO::getManagerId).collect(Collectors.toSet());
        if (!userIdSet.isEmpty()) {
            Collection<User> managers = userService.listByIds(userIdSet);
            Map<Integer, User> managerMap = MapUtil.collectionToMap(managers, User::getId);
            resultList.forEach(r -> {
                if (r.getManagerId() != null) {
                    User manager = managerMap.get(r.getManagerId());
                    if (manager != null) {
                        r.setManagerName(manager.getName());
                        r.setManagerPhone(manager.getPhone());
                    }
                }
            });
        }
        return new Page<CommunityActionDTO>(communityPage.getCurrent(), communityPage.getSize(), communityPage.getTotal()).setRecords(resultList);
    }

    @Override
    public Integer countHospitalIn(Date date) {
        // 预约到院人数 预约总人数
        // type = 1/2
        return applyPostService.lambdaQuery()
                .between(ApplyPost::getAppointmentTime, DateUtil.getDateBegin(date), DateUtil.getDateEnd(date))
                .eq(ApplyPost::getState, 1)
                .in(ApplyPost::getType, 1, 2)
                .count();
    }

    @Override
    public Integer countHospitalOut(Date date) {
        // 已经到院人数 扫进人数+1
        return userActionMapper.countScanUserCount(DateUtil.getDate(date, "yyyyMMdd"), 1);
    }

    @Override
    public Integer countHospitalWait(Date date) {
        // 院内等待人数 扫进人数+1  扫出人数-1
        int c1 = userActionMapper.countScanUserCount(DateUtil.getDate(date, "yyyyMMdd"), 1);
        int c2 = userActionMapper.countScanUserCount(DateUtil.getDate(date, "yyyyMMdd"), 2);
        return Math.max(0, c1 - c2);
    }
}
